#include "StdDevice_SPI.h"
#include "StdDevice_common.h"

#define LOG __platform_printf


static pika_dev* _get_dev(PikaObj* self) {
    pika_dev* dev = PIKA_HAL_OBJ2DEV(self);
    if (NULL != dev) {
        return dev;
    }
    dev = pika_hal_open(PIKA_HAL_SPI, obj_getStr(self, "name"));
    if (NULL == dev) {
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] open SPI '%s' failed.",
                          obj_getStr(self, "name"));
        return NULL;
    }
    obj_setPtr(self, "pika_dev", dev);
    return dev;

}

static void _free_dev(pika_dev* dev){
    if (NULL != dev && NULL != dev->ioctl_config) {
        pikaFree(dev->ioctl_config, sizeof(pika_hal_SPI_config));
        dev->ioctl_config = NULL;
    }
    if (NULL != dev) {
        pikaFree(dev, sizeof(pika_dev));
    }
}

void StdDevice_SPI___init__(PikaObj *self, char* name){
    obj_setPtr(self, "pika_dev", NULL);
    obj_setStr(self, "name", name);
}


/**
 * StdDevice_SPI_open 函数
 * cs_obj： CS脚GPIO对象
 * mode： 时钟极性/工作模式
 * data_width：数据位数
 * lsb_or_msb：低位在前还是高位在前
 * master_or_slave： 主机模式还是从机模式
 * speed：传输速率
 * duplex：全双工还是半双工
 */
void StdDevice_SPI_open(PikaObj *self, Arg* cs_name, int mode, int data_width, int lsb_or_msb, int master_or_slave, int speed, int duplex){
    pika_dev* dev = _get_dev(self);
    pika_hal_SPI_config cfg = {0};
    ArgType cs_type = arg_getType(cs_name);
    pika_dev* cs_dev;
    switch (cs_type)
    {
        case ARG_TYPE_STRING:
            cs_dev = pika_hal_open(PIKA_HAL_GPIO, arg_getStr(cs_name));
            if (cs_dev == NULL){
                obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
                obj_setSysOut(self, "[ERROR] CS's pika_dev should not be NULL.");
                return;
            }
            cfg.CS = cs_dev;
            break;
        case ARG_TYPE_NONE:
            cfg.CS = NULL;
            break;
        default:
            obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM);
            obj_setSysOut(self, "[ERROR] cs's type should be StdDevice.GPIO or None.");
            return;
            break;
    }
    
    cfg.mode = mode;
    cfg.speed = speed;
    cfg.master_or_slave = master_or_slave;
    cfg.data_width = data_width;
    cfg.lsb_or_msb = lsb_or_msb;
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg);
}

void StdDevice_SPI_close(PikaObj *self){
    pika_dev* dev = _get_dev(self);
    pika_hal_SPI_config* cfg_ptr = dev->platform_data;
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE);
    pika_hal_close(dev);
    obj_setPtr(self, "pika_dev", NULL);
}



Arg* StdDevice_SPI_read(PikaObj *self, int length){
    #if 1
    pika_dev* dev = _get_dev(self);
    uint8_t* databuff = (uint8_t*)pikaMalloc(length + 1);
    if (NULL == databuff) {
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] not enough memory.");
        return NULL;
    }
    int ret = pika_hal_read(dev, databuff, length);
    if (ret < 0) {
        pikaFree(databuff, length + 1);
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] SPI read fail.");
        return NULL;
    }
    Arg* res = arg_newBytes(databuff, length);
    pikaFree(databuff, length + 1);
    return res;
    #endif

    #if 0 //直接改buff长度，不知道会不会有隐藏的内存溢出，要小心验证
    Arg* bytes_obj = arg_newBytes(NULL, length + 1);
    pika_dev* dev = _get_dev(self);
    int _readlen = pika_hal_read(dev, arg_getBytes(bytes_obj), length);
    if (_readlen < 0){
        arg_deinit(bytes_obj); //必须arg_deinit，否则有内存溢出
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] hal read fail.");
        return NULL;
    }
    size_t len_get = _readlen;
    //手动改写Bytes对象的长度
    void* content = arg_getContent(bytes_obj);
    pika_platform_memcpy(content, &len_get, sizeof(size_t));
    return bytes_obj;
    #endif

}

void StdDevice_SPI_write(PikaObj *self, uint8_t* data, int length){
    pika_dev* dev = _get_dev(self);
    int res = pika_hal_write(dev, data, length);
    if (res < 0){
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] write fail.");
        return;
    }
}


char* StdDevice_SPI_get_name(PikaObj *self){
    return obj_getStr(self, "name");
}


void StdDevice_SPI___del__(PikaObj *self){
    pika_dev* dev = PIKA_HAL_OBJ2DEV(self);
    if (NULL != dev && NULL != dev->ioctl_config) {
        pikaFree(dev->ioctl_config, sizeof(pika_hal_SPI_config));
        dev->ioctl_config = NULL;
    }
    if (NULL != dev) {
        pikaFree(dev, sizeof(pika_dev));
    }
}


// void StdDevice_SPI_enable_IT(PikaObj *self, int irq, Arg* evt_cbk){
// }

// void StdDevice_SPI_disable_IT(PikaObj *self, int irq){
// }

// Arg* StdDevice_SPI_write_read(PikaObj *self, uint8_t* data, int length){

// }

void StdDevice_SPI_remap(PikaObj *self, char *mosi, char *miso, char* sclk){

}


